feat: 为 @nutui/nutui-react-taro 补齐 AI-Coding 能力(CLI / MCP / Skill + 站点文档) - #3500
Conversation
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (47)
💤 Files with no reviewable changes (2)
Walkthrough新增可配置的 CLI core、Taro CLI 与 MCP 能力,统一 H5/Taro 数据快照生成流程,并扩展属性元数据与相关文档、技能说明。 ChangesCLI 平台化与 Taro 支持
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant TaroCLI
participant CoreCLI
participant DataSnapshot
participant MCPClient
User->>TaroCLI: nutui-react-taro command
TaroCLI->>CoreCLI: runCli(config, argv)
CoreCLI->>DataSnapshot: loadMeta/readDoc/readDemo
DataSnapshot-->>CoreCLI: component data
MCPClient->>TaroCLI: MCP tool request
TaroCLI-->>MCPClient: structured tool result
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## feat_v4.x #3500 +/- ##
=============================================
+ Coverage 88.33% 88.44% +0.10%
=============================================
Files 295 296 +1
Lines 19747 19812 +65
Branches 3117 3134 +17
=============================================
+ Hits 17443 17522 +79
+ Misses 2298 2284 -14
Partials 6 6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (3)
packages/nutui-react-cli-core/src/mcp/tools.ts (1)
46-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
isError的判定比toMcpResult宽松。这里只检查
'error' in x,而toMcpResult还要求error === true。目前Component没有error字段,所以行为正确;但两处判定不一致,后续给Component加同名字段就会静默把组件当错误处理。建议对齐为同一个谓词。♻️ 建议对齐判定
function isError(x: unknown): x is ReturnType<typeof createError> { - return !!x && typeof x === 'object' && 'error' in x + return ( + !!x && + typeof x === 'object' && + (x as { error?: unknown }).error === true + ) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nutui-react-cli-core/src/mcp/tools.ts` around lines 46 - 48, 统一 isError 与 toMcpResult 的错误判定条件:在 isError 中不仅检查对象包含 error 属性,还必须验证其值为 true。保持 createError 返回类型保护及其他调用方行为不变,确保带有非布尔或 false 值 error 字段的 Component 不会被识别为错误。packages/nutui-react-taro-cli/tsup.config.ts (1)
1-4: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win让版本读取相对于配置文件,而不是当前工作目录。
Line 4 的路径由
process.cwd()解析;若从 monorepo 根目录直接调用 tsup,可能读取根package.json,导致__CLI_VERSION__注入错误版本。请改为基于import.meta.url定位本包的package.json,或确认 CI/发布脚本始终在该包目录执行。建议修改
import { readFileSync } from 'node:fs' +import { fileURLToPath } from 'node:url' import { defineConfig } from 'tsup' -const { version } = JSON.parse(readFileSync('package.json', 'utf-8')) +const packageJson = fileURLToPath(new URL('./package.json', import.meta.url)) +const { version } = JSON.parse(readFileSync(packageJson, 'utf-8'))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nutui-react-taro-cli/tsup.config.ts` around lines 1 - 4, 将 tsup 配置中读取 package.json 的逻辑改为相对于配置文件位置解析,使用 import.meta.url 定位本包的 package.json,避免依赖 process.cwd() 导致从 monorepo 根目录执行时读取错误版本。保持 version 解析及后续 __CLI_VERSION__ 注入行为不变。scripts/build-meta.mjs (1)
306-309: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win摘要与实际代码不一致:未打印 taro 端缺失 API 表组件列表。
变更说明称"在存在'无 API 表(taro)'组件时打印对应组件列表",但实际代码只对
noApiIds(H5)做了if (noApiIds.length) console.log(...),noApiTaroIds仅用于计算apiTaroComponentCount,从未被打印,H5/taro 两端诊断信息不对称。♻️ 建议补充 taro 端缺失组件打印,保持两端一致
if (noApiIds.length) { console.log(` 无 API 表(H5)的组件 (${noApiIds.length}): ${noApiIds.join(', ')}`) } + if (noApiTaroIds.length) { + console.log(` 无 API 表(taro)的组件 (${noApiTaroIds.length}): ${noApiTaroIds.join(', ')}`) + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/build-meta.mjs` around lines 306 - 309, 在构建元数据输出逻辑中补充对 noApiTaroIds 的条件打印:参照 noApiIds 的输出方式,当 noApiTaroIds.length 大于零时打印 taro 端缺失 API 表组件数量及组件列表,保持与 H5 端诊断信息一致。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/nutui-react-cli-core/package.json`:
- Around line 1-22: 同步更新 pnpm-lock.yaml 以匹配
packages/nutui-react-cli-core/package.json 中新增的 dependencies 和
devDependencies;在仓库根目录运行非 frozen-lockfile 模式的 pnpm
install,确认生成该包的依赖条目及对应解析版本,并提交更新后的锁文件。
In `@packages/nutui-react-cli-core/scripts/prepare-data.mjs`:
- Around line 21-56: Update regenerateMeta and the shared meta generation flow
to serialize writes to meta/components.json using a temporary output followed by
an atomic rename, preventing concurrent prepare-data executions from
interleaving. In readMeta, distinguish a missing BUILD_META_SCRIPT
(published-package fallback) from an existing script that fails: propagate the
latter error and fail the build even when an old META_PATH exists, while
preserving fallback only for the missing-script case. Verify the nutui-react-cli
and nutui-react-taro-cli prepare-data orchestration does not invoke these
generators concurrently.
In `@packages/nutui-react-cli-core/src/data.ts`:
- Around line 64-70: 在 MCP 调用处校验 params.lang 必须属于 config.langs,并更新 readDoc
以拒绝包含路径分隔符的 lang;同时通过 path.resolve 验证最终文件路径仍位于组件的 docs 目录内,越界时返回 null。
In `@packages/nutui-react-cli-core/src/mcp/tools.ts`:
- Around line 210-247: 在 doc 和 demo 分支中分别对 params.lang 与 params.name
执行服务端白名单校验,不要依赖 inputSchema 的 enum;仅允许配置支持的语言以及 listDemos(config.dataDir, comp)
返回的示例名,校验失败时通过现有 toMcpResult/createError 错误流程返回,并仅在校验通过后调用 readDoc 或
readDemo,确保输入不能用于路径遍历。
In `@packages/nutui-react-cli/package.json`:
- Around line 45-48: 调整 packages/nutui-react-cli 的依赖分区:将 yargs 从 dependencies 移回
devDependencies,并在 devDependencies 中补回 `@modelcontextprotocol/sdk`,确保
tsup.config.ts 的 noExternal 列表中这两个包及 `@nutui/nutui-react-cli-core` 都有显式依赖声明。
In `@packages/nutui-react-taro-cli/package.json`:
- Around line 46-55: 同步更新根目录 pnpm-lock.yaml,使
packages/nutui-react-taro-cli/package.json 中的依赖声明与锁文件 specifier 完全一致。运行 pnpm
install 生成锁文件后,使用 pnpm install --frozen-lockfile 验证安装成功,不要关闭 frozen-lockfile 检查。
In `@packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md`:
- Around line 130-133: Update the --format json documentation to state that it
applies to all query commands and explicitly excludes mcp, which uses MCP stdio
rather than the CLI format parameter. Apply this wording consistently in
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md lines 130-133,
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md lines 11-14, and
src/sites/sites-react/doc/docs/ai-taro/cli.md lines 11-14.
- Around line 12-13: 统一固定 CLI 与 Skill 工具版本:在
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md 的
allowed-tools、Skill 示例和 MCP 配置中使用明确版本,并同步调整命令匹配模式;在
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md 的 npm/npx 与 skills 示例、以及
src/sites/sites-react/doc/docs/ai-taro/cli.md
的对应示例中使用相同固定版本,确保所有文档和配置保持一致。涉及位置:SKILL.md 12-13、25-32、98-103;cli.en-US.md
20-28、76-80;cli.md 20-28、76-80。
---
Nitpick comments:
In `@packages/nutui-react-cli-core/src/mcp/tools.ts`:
- Around line 46-48: 统一 isError 与 toMcpResult 的错误判定条件:在 isError 中不仅检查对象包含 error
属性,还必须验证其值为 true。保持 createError 返回类型保护及其他调用方行为不变,确保带有非布尔或 false 值 error 字段的
Component 不会被识别为错误。
In `@packages/nutui-react-taro-cli/tsup.config.ts`:
- Around line 1-4: 将 tsup 配置中读取 package.json 的逻辑改为相对于配置文件位置解析,使用 import.meta.url
定位本包的 package.json,避免依赖 process.cwd() 导致从 monorepo 根目录执行时读取错误版本。保持 version 解析及后续
__CLI_VERSION__ 注入行为不变。
In `@scripts/build-meta.mjs`:
- Around line 306-309: 在构建元数据输出逻辑中补充对 noApiTaroIds 的条件打印:参照 noApiIds 的输出方式,当
noApiTaroIds.length 大于零时打印 taro 端缺失 API 表组件数量及组件列表,保持与 H5 端诊断信息一致。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 986bda10-2aee-483d-bfaa-8d72c625f27e
📒 Files selected for processing (47)
package.jsonpackages/nutui-react-cli-core/.gitignorepackages/nutui-react-cli-core/package.jsonpackages/nutui-react-cli-core/scripts/prepare-data.mjspackages/nutui-react-cli-core/src/cli.tspackages/nutui-react-cli-core/src/commands/_shared.tspackages/nutui-react-cli-core/src/commands/demo.tspackages/nutui-react-cli-core/src/commands/doc.tspackages/nutui-react-cli-core/src/commands/info.tspackages/nutui-react-cli-core/src/commands/list.tspackages/nutui-react-cli-core/src/commands/mcp.tspackages/nutui-react-cli-core/src/commands/token.tspackages/nutui-react-cli-core/src/config.tspackages/nutui-react-cli-core/src/data.tspackages/nutui-react-cli-core/src/error.tspackages/nutui-react-cli-core/src/format.tspackages/nutui-react-cli-core/src/index.tspackages/nutui-react-cli-core/src/mcp/prompts.tspackages/nutui-react-cli-core/src/mcp/tools.tspackages/nutui-react-cli-core/src/types.tspackages/nutui-react-cli-core/tsconfig.jsonpackages/nutui-react-cli/package.jsonpackages/nutui-react-cli/scripts/prepare-data.mjspackages/nutui-react-cli/src/cli.tspackages/nutui-react-cli/src/mcp/prompts.tspackages/nutui-react-cli/src/mcp/tools.tspackages/nutui-react-cli/tsup.config.tspackages/nutui-react-taro-cli/.gitignorepackages/nutui-react-taro-cli/README.mdpackages/nutui-react-taro-cli/package.jsonpackages/nutui-react-taro-cli/scripts/prepare-data.mjspackages/nutui-react-taro-cli/skills/.npmignorepackages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.mdpackages/nutui-react-taro-cli/src/cli.tspackages/nutui-react-taro-cli/tsconfig.jsonpackages/nutui-react-taro-cli/tsup.config.tspnpm-workspace.yamlscripts/build-meta.mjsscripts/create-properties.jsscripts/properties-taro.jsonscripts/properties.jsonsrc/sites/sites-react/doc/docs/ai-taro/cli.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/cli.mdsrc/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/for-agents.mdsrc/sites/sites-react/doc/docs/ai-taro/mcp.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/mcp.md
💤 Files with no reviewable changes (2)
- packages/nutui-react-cli/src/mcp/tools.ts
- packages/nutui-react-cli/src/mcp/prompts.ts
| function regenerateMeta() { | ||
| if (!fs.existsSync(BUILD_META_SCRIPT)) { | ||
| // 脱离 monorepo(如已发布包被重新 build),无源码可生成,沿用现有快照。 | ||
| console.log('ℹ️ 未找到 build-meta 脚本,跳过 meta 重生成(沿用现有快照)') | ||
| return | ||
| } | ||
| console.log('🔄 重新生成 meta/components.json(generate:meta)...') | ||
| execFileSync(process.execPath, [BUILD_META_SCRIPT], { stdio: 'inherit' }) | ||
| } | ||
|
|
||
| function readMeta() { | ||
| try { | ||
| regenerateMeta() | ||
| } catch (err) { | ||
| // meta 生成失败:有旧快照则告警后沿用,否则无从继续。 | ||
| if (fs.existsSync(META_PATH)) { | ||
| console.warn( | ||
| `⚠️ meta 重生成失败(${err.message}),沿用现有 ${path.relative(REPO_ROOT, META_PATH)}` | ||
| ) | ||
| } else { | ||
| console.error( | ||
| `❌ meta 重生成失败且无现有快照:${err.message}\n` + | ||
| ` 请在仓库根手动执行:npm run generate:meta` | ||
| ) | ||
| process.exit(1) | ||
| } | ||
| } | ||
| if (!fs.existsSync(META_PATH)) { | ||
| console.error( | ||
| `❌ 未找到 ${path.relative(REPO_ROOT, META_PATH)}。\n` + | ||
| ` 它是构建产物,请先在仓库根执行:npm run generate:meta` | ||
| ) | ||
| process.exit(1) | ||
| } | ||
| return JSON.parse(fs.readFileSync(META_PATH, 'utf-8')) | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
共享文件 meta/components.json 存在潜在并发写入风险,且失败时静默回退。
regenerateMeta() 会对仓库根共享文件 meta/components.json 执行"子进程重新生成",而该函数会被 nutui-react-cli 与 nutui-react-taro-cli 两个叶子包各自的 prepare-data.mjs 分别调用。如果两者的 prepare-data 脚本在 CI/构建流水线中被并行触发(例如通过 pnpm -r --parallel 之类的编排),会出现对同一文件的并发"生成+写入",存在数据损坏(TOCTOU/写入交叉)的风险。
此外,readMeta() 在 monorepo 内 regenerateMeta() 失败但存在旧快照时,只会 console.warn 并继续使用旧快照(Line 36-39),不会让构建失败,这可能掩盖 properties.json / build-meta.mjs 管线中的真实回归,导致 CLI 数据快照静默使用过期数据。
建议:
- 为共享的
meta/components.json写入增加临时文件+原子 rename,或在编排层确保prepare-data脚本串行执行,避免并发写入同一文件。 - 考虑将"monorepo 内脚本存在但执行失败"与"脱离 monorepo 无脚本"两种场景区分处理:前者应让构建失败(而非仅告警),避免静默使用过期数据。
请确认这两个叶子包的 prepare-data 脚本在实际构建/发布流程中是否存在并行调用的可能。
#!/bin/bash
# 检查是否存在跨包并行调用 prepare-data 的编排脚本
rg -n 'prepare-data' --type=json --type=yaml -g '!node_modules' -C2
rg -nP '"prepare-data"' package.json packages/*/package.json -C2
fd -g 'turbo.json' -x cat {}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-cli-core/scripts/prepare-data.mjs` around lines 21 - 56,
Update regenerateMeta and the shared meta generation flow to serialize writes to
meta/components.json using a temporary output followed by an atomic rename,
preventing concurrent prepare-data executions from interleaving. In readMeta,
distinguish a missing BUILD_META_SCRIPT (published-package fallback) from an
existing script that fails: propagate the latter error and fail the build even
when an old META_PATH exists, while preserving fallback only for the
missing-script case. Verify the nutui-react-cli and nutui-react-taro-cli
prepare-data orchestration does not invoke these generators concurrently.
| export function readDoc( | ||
| dataDir: string, | ||
| component: Component, | ||
| lang: Lang | ||
| ): string | null { | ||
| const file = path.join(dataDir, 'docs', component.id, `${lang}.md`) | ||
| return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
限制 lang,避免 MCP 文档读取路径穿越。
Line 69 直接将运行时 lang 拼入路径;MCP 处理器会把未校验的 params.lang 传入这里。../../… 可逃逸组件文档目录并读取可访问的 .md 文件。应在调用处校验其属于 config.langs,并在此处额外拒绝路径分隔符或通过 path.resolve 验证目标仍位于文档目录内。
建议修复
export function readDoc(
dataDir: string,
component: Component,
lang: Lang
): string | null {
+ if (lang.includes('/') || lang.includes('\\') || lang.includes('..')) {
+ return null
+ }
const file = path.join(dataDir, 'docs', component.id, `${lang}.md`)
return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function readDoc( | |
| dataDir: string, | |
| component: Component, | |
| lang: Lang | |
| ): string | null { | |
| const file = path.join(dataDir, 'docs', component.id, `${lang}.md`) | |
| return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null | |
| export function readDoc( | |
| dataDir: string, | |
| component: Component, | |
| lang: Lang | |
| ): string | null { | |
| if (lang.includes('/') || lang.includes('\\') || lang.includes('..')) { | |
| return null | |
| } | |
| const file = path.join(dataDir, 'docs', component.id, `${lang}.md`) | |
| return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null | |
| } |
🧰 Tools
🪛 ast-grep (0.45.0)
[warning] 69-69: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(file, 'utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-cli-core/src/data.ts` around lines 64 - 70, 在 MCP 调用处校验
params.lang 必须属于 config.langs,并更新 readDoc 以拒绝包含路径分隔符的 lang;同时通过 path.resolve
验证最终文件路径仍位于组件的 docs 目录内,越界时返回 null。
Source: Linters/SAST tools
| case 'doc': { | ||
| const comp = resolve(config, meta, params.component as string) | ||
| if (isError(comp)) return toMcpResult(comp) | ||
| const lang = (params.lang as Lang) ?? config.defaultLang | ||
| const content = readDoc(config.dataDir, comp, lang) | ||
| if (content === null) { | ||
| const langName = config.langLabel[lang] ?? lang | ||
| return toMcpResult( | ||
| createError( | ||
| ErrorCodes.DOC_NOT_FOUND, | ||
| `${comp.name} ${comp.cName} 暂无${langName}文档。` | ||
| ) | ||
| ) | ||
| } | ||
| return toMcpResult({ name: comp.name, lang, doc: content }) | ||
| } | ||
|
|
||
| case 'demo': { | ||
| const comp = resolve(config, meta, params.component as string) | ||
| if (isError(comp)) return toMcpResult(comp) | ||
| const demos = listDemos(config.dataDir, comp) | ||
| const demoName = params.name as string | undefined | ||
| if (!demoName) { | ||
| return toMcpResult({ component: comp.name, demos }) | ||
| } | ||
| const code = readDemo(config.dataDir, comp, demoName) | ||
| if (code === null) { | ||
| return toMcpResult( | ||
| createError( | ||
| ErrorCodes.DEMO_NOT_FOUND, | ||
| `${comp.name} 未找到示例「${demoName}」。`, | ||
| demos.length | ||
| ? `可选:${demos.join(' / ')}` | ||
| : `该组件暂无 ${config.demoLabel} 示例。` | ||
| ) | ||
| ) | ||
| } | ||
| return toMcpResult({ component: comp.name, demo: demoName, code }) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
lang 与 name 未做白名单校验,存在路径遍历读取任意文件的风险。
params.lang、params.name 直接透传给 readDoc / readDemo,两者均用 path.join(dataDir, ...) 拼接文件名。inputSchema 的 enum 只是给客户端的提示,MCP SDK 不会强制校验入参,因此 lang: '../../../../etc/passwd' 之类的值可逃出 dataDir 并把文件内容返回给 Agent。component 走 resolveComponent 已被白名单化,这两个参数是缺口。
🔒️ 建议的校验修复
case 'doc': {
const comp = resolve(config, meta, params.component as string)
if (isError(comp)) return toMcpResult(comp)
- const lang = (params.lang as Lang) ?? config.defaultLang
+ const rawLang = (params.lang as string) ?? config.defaultLang
+ if (!config.langs.includes(rawLang)) {
+ return toMcpResult(
+ createError(
+ ErrorCodes.DOC_NOT_FOUND,
+ `不支持的文档语言「${rawLang}」,可选:${config.langs.join(' / ')}。`
+ )
+ )
+ }
+ const lang = rawLang as Lang
const content = readDoc(config.dataDir, comp, lang) const demos = listDemos(config.dataDir, comp)
const demoName = params.name as string | undefined
if (!demoName) {
return toMcpResult({ component: comp.name, demos })
}
+ if (!demos.includes(demoName)) {
+ return toMcpResult(
+ createError(
+ ErrorCodes.DEMO_NOT_FOUND,
+ `${comp.name} 未找到示例「${demoName}」。`,
+ demos.length
+ ? `可选:${demos.join(' / ')}`
+ : `该组件暂无 ${config.demoLabel} 示例。`
+ )
+ )
+ }
const code = readDemo(config.dataDir, comp, demoName)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case 'doc': { | |
| const comp = resolve(config, meta, params.component as string) | |
| if (isError(comp)) return toMcpResult(comp) | |
| const lang = (params.lang as Lang) ?? config.defaultLang | |
| const content = readDoc(config.dataDir, comp, lang) | |
| if (content === null) { | |
| const langName = config.langLabel[lang] ?? lang | |
| return toMcpResult( | |
| createError( | |
| ErrorCodes.DOC_NOT_FOUND, | |
| `${comp.name} ${comp.cName} 暂无${langName}文档。` | |
| ) | |
| ) | |
| } | |
| return toMcpResult({ name: comp.name, lang, doc: content }) | |
| } | |
| case 'demo': { | |
| const comp = resolve(config, meta, params.component as string) | |
| if (isError(comp)) return toMcpResult(comp) | |
| const demos = listDemos(config.dataDir, comp) | |
| const demoName = params.name as string | undefined | |
| if (!demoName) { | |
| return toMcpResult({ component: comp.name, demos }) | |
| } | |
| const code = readDemo(config.dataDir, comp, demoName) | |
| if (code === null) { | |
| return toMcpResult( | |
| createError( | |
| ErrorCodes.DEMO_NOT_FOUND, | |
| `${comp.name} 未找到示例「${demoName}」。`, | |
| demos.length | |
| ? `可选:${demos.join(' / ')}` | |
| : `该组件暂无 ${config.demoLabel} 示例。` | |
| ) | |
| ) | |
| } | |
| return toMcpResult({ component: comp.name, demo: demoName, code }) | |
| case 'doc': { | |
| const comp = resolve(config, meta, params.component as string) | |
| if (isError(comp)) return toMcpResult(comp) | |
| const rawLang = (params.lang as string) ?? config.defaultLang | |
| if (!config.langs.includes(rawLang)) { | |
| return toMcpResult( | |
| createError( | |
| ErrorCodes.DOC_NOT_FOUND, | |
| `不支持的文档语言「${rawLang}」,可选:${config.langs.join(' / ')}。` | |
| ) | |
| ) | |
| } | |
| const lang = rawLang as Lang | |
| const content = readDoc(config.dataDir, comp, lang) | |
| if (content === null) { | |
| const langName = config.langLabel[lang] ?? lang | |
| return toMcpResult( | |
| createError( | |
| ErrorCodes.DOC_NOT_FOUND, | |
| `${comp.name} ${comp.cName} 暂无${langName}文档。` | |
| ) | |
| ) | |
| } | |
| return toMcpResult({ name: comp.name, lang, doc: content }) | |
| } | |
| case 'demo': { | |
| const comp = resolve(config, meta, params.component as string) | |
| if (isError(comp)) return toMcpResult(comp) | |
| const demos = listDemos(config.dataDir, comp) | |
| const demoName = params.name as string | undefined | |
| if (!demoName) { | |
| return toMcpResult({ component: comp.name, demos }) | |
| } | |
| if (!demos.includes(demoName)) { | |
| return toMcpResult( | |
| createError( | |
| ErrorCodes.DEMO_NOT_FOUND, | |
| `${comp.name} 未找到示例「${demoName}」。`, | |
| demos.length | |
| ? `可选:${demos.join(' / ')}` | |
| : `该组件暂无 ${config.demoLabel} 示例。` | |
| ) | |
| ) | |
| } | |
| const code = readDemo(config.dataDir, comp, demoName) | |
| if (code === null) { | |
| return toMcpResult( | |
| createError( | |
| ErrorCodes.DEMO_NOT_FOUND, | |
| `${comp.name} 未找到示例「${demoName}」。`, | |
| demos.length | |
| ? `可选:${demos.join(' / ')}` | |
| : `该组件暂无 ${config.demoLabel} 示例。` | |
| ) | |
| ) | |
| } | |
| return toMcpResult({ component: comp.name, demo: demoName, code }) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-cli-core/src/mcp/tools.ts` around lines 210 - 247, 在 doc
和 demo 分支中分别对 params.lang 与 params.name 执行服务端白名单校验,不要依赖 inputSchema 的
enum;仅允许配置支持的语言以及 listDemos(config.dataDir, comp) 返回的示例名,校验失败时通过现有
toMcpResult/createError 错误流程返回,并仅在校验通过后调用 readDoc 或 readDemo,确保输入不能用于路径遍历。
| "yargs": "^17.7.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@nutui/nutui-react-cli-core": "workspace:*", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
依赖分区与 noExternal bundle 列表已脱节。
tsup.config.ts 把 yargs、@modelcontextprotocol/sdk、@nutui/nutui-react-cli-core 全部 noExternal,产物号称自包含:
yargs移入dependencies会让终端用户在npx时多装一份已被内联的包,与「零安装依赖即可运行」相悖,放回devDependencies更一致。@modelcontextprotocol/sdk从devDependencies移除但仍在noExternal中。它现在只能靠 core 包的node_modules被解析到;pnpm 严格隔离下这属于隐式依赖,core 一旦调整依赖或安装布局变化,本包构建就会失败。建议保留为本包devDependencies。
#!/bin/bash
# 本包依赖声明现状
fd -t f 'package.json' packages/nutui-react-cli -d 1 | xargs -r jq '{version, dependencies, devDependencies}'
# core 包是否显式声明 sdk 与 yargs
fd -t f 'package.json' packages/nutui-react-cli-core -d 1 | xargs -r jq '{name, private, dependencies, devDependencies, peerDependencies}'
# Taro CLI 包的分区是否与本包一致
fd -t f 'package.json' packages/nutui-react-taro-cli -d 1 | xargs -r jq '{dependencies, devDependencies}'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-cli/package.json` around lines 45 - 48, 调整
packages/nutui-react-cli 的依赖分区:将 yargs 从 dependencies 移回 devDependencies,并在
devDependencies 中补回 `@modelcontextprotocol/sdk`,确保 tsup.config.ts 的 noExternal
列表中这两个包及 `@nutui/nutui-react-cli-core` 都有显式依赖声明。
| ## Key Rules | ||
|
|
||
| 1. **Always query before writing** — Don't guess NutUI Taro APIs, prop names, or enum values from memory. Run `nutui-react-taro info` (and `nutui-react-taro demo` for a working example) first. Taro props can differ from the H5 package. | ||
| 2. **Use `--format json`** — Every command supports it. Parse the JSON output rather than regex-matching the human-readable text. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
统一修正 --format json 的适用范围。 mcp 命令使用 MCP stdio 协议,不消费 CLI 的 format 参数;因此不应描述为所有命令都输出 CLI JSON。
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md#L130-L133:改为“所有查询命令支持”,并排除mcp。src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md#L11-L14:将 “Every command” 改为查询命令。src/sites/sites-react/doc/docs/ai-taro/cli.md#L11-L14:将“所有命令”改为查询命令。
🧰 Tools
🪛 SkillSpector (2.4.4)
[warning] 13: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
[warning] 26: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
[warning] 32: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
[warning] 1: [RP1] null: MCP server references in the skill manifest without version pinning are a rug-pull risk.
Remediation: Always pin MCP server versions in manifest references.
(MCP Rug Pull (RP1))
📍 Affects 3 files
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md#L130-L133(this comment)src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md#L11-L14src/sites/sites-react/doc/docs/ai-taro/cli.md#L11-L14
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md` around lines
130 - 133, Update the --format json documentation to state that it applies to
all query commands and explicitly excludes mcp, which uses MCP stdio rather than
the CLI format parameter. Apply this wording consistently in
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md lines 130-133,
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md lines 11-14, and
src/sites/sites-react/doc/docs/ai-taro/cli.md lines 11-14.
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (2)
scripts/build-meta.mjs (1)
306-310: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
noApiTaroIds只参与计数,未输出明细。 H5 侧会列出缺少 API 表的组件 id,taro 侧同样收集了noApiTaroIds却没有打印,排查 Taro 端缺表组件时只能看到一个总数。🔎 建议补充 taro 侧明细输出
if (noApiIds.length) { console.log(` 无 API 表(H5)的组件 (${noApiIds.length}): ${noApiIds.join(', ')}`) } + if (noApiTaroIds.length) { + console.log(` 无 API 表(taro)的组件 (${noApiTaroIds.length}): ${noApiTaroIds.join(', ')}`) + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/build-meta.mjs` around lines 306 - 310, 在构建元数据的汇总输出中补充 noApiTaroIds 的明细日志:参考 noApiIds 的条件判断和输出格式,当 noApiTaroIds 非空时打印缺少 Taro API 表的组件数量及其 ID 列表,保留现有 H5 输出不变。packages/nutui-react-cli-core/scripts/prepare-data.mjs (1)
58-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value注释与实现不一致。 该函数并未使用 posix
basename(basename 由调用方在 demos 分支处理),注释容易误导后续维护者。📝 建议修正注释
-// meta 里的路径始终是 posix 相对仓库根路径,用 posix 取 basename,再 join 到本地。 +// meta 里的路径始终是 posix 相对仓库根路径,这里按仓库根解析后复制到目标绝对路径。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nutui-react-cli-core/scripts/prepare-data.mjs` around lines 58 - 65, 更新 copyRepoFile 上方注释,使其准确描述函数当前行为:relPosixPath 作为相对仓库根路径用于拼接源文件路径;移除关于使用 posix basename 或由该函数执行本地 join 的误导性表述。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/nutui-react-cli-core/src/data.ts`:
- Around line 62-71: 在 readDoc 中先校验 lang 不包含路径分隔符“/”或“\”,发现非法值时直接返回
null,再执行现有的文档路径拼接与读取逻辑;保持合法语言值及文件不存在时的行为不变,并与 readDemo 的防护方式一致。
In `@packages/nutui-react-cli-core/src/mcp/tools.ts`:
- Around line 210-225: 在 MCP 请求处理的 doc 分支中校验
params.lang,仅允许配置支持的语言值,并拒绝包含路径分隔符或其他非法路径片段的输入;校验通过后再调用
readDoc,确保外部输入不会被拼接为任意文件路径。复用 readDemo 的语言白名单校验方式,并保留默认语言处理逻辑。
In `@packages/nutui-react-taro-cli/README.md`:
- Line 106: 将 packages/nutui-react-taro-cli/README.md 第106行的 skills add
命令、src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md 第24行及
src/sites/sites-react/doc/docs/ai-taro/for-agents.md 第24行的相关 npx 命令统一改为带 -y
参数,覆盖 skills add 和 `@nutui/nutui-react-taro-cli` info Button,确保首次执行时保持非交互式。
- Around line 73-86: Update the MCP configuration documentation in
packages/nutui-react-taro-cli/README.md (lines 73-86),
src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md (lines 31-42),
src/sites/sites-react/doc/docs/ai-taro/for-agents.md (lines 29-42),
src/sites/sites-react/doc/docs/ai-taro/mcp.en-US.md (lines 36-47), and
src/sites/sites-react/doc/docs/ai-taro/mcp.md (lines 36-47) to preserve
mcpServers for Claude and Cursor while providing a separate VS Code
.vscode/mcp.json example using the top-level servers field.
In `@packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md`:
- Around line 11-14: 统一锁定 CLI、Skill 和 MCP 使用的 `@nutui/nutui-react-taro-cli`
精确版本,移除“始终使用最新版”等未锁定表述。更新
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md 的
allowed-tools(11-14)、CLI 示例(23-32)及 MCP args(98-104);更新
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md(24-28、76-80)和
src/sites/sites-react/doc/docs/ai-taro/cli.md(24-28、76-80),将 npx、npm i -D 及
skills add 命令统一使用同一明确版本。
In `@scripts/properties-taro.json`:
- Around line 3082-3091: 修正源文档 doc.taro.md 中 Form.labelPosition
表格行的反引号与竖线转义,使类型和默认值分别正确解析为 'top' 与 'left';同时将 Row.onClick 的英文说明 “Fired when
clicked” 改为与中文文档一致的描述。完成后重新执行 npm run generate:props:taro 生成
scripts/properties-taro.json,勿直接修改生成文件。
In `@scripts/properties.json`:
- Around line 7615-7621: 修正 doc.md 中 Popup.portal 和 TextArea.status
的类型字符串,移除多余的反引号并保持类型内容准确;随后运行 npm run generate:props,更新由属性文档生成的站点 API 表及
llms/MCP 输出。
In `@src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md`:
- Around line 85-89: Update all four documented MCP links in
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md lines 85-89 and 91, and
src/sites/sites-react/doc/docs/ai-taro/cli.md lines 85-89 and 91, to preserve
the Taro route context: use /en-US/ai-taro/mcp and /en-US/ai-taro/for-agents in
the English page, and /zh-CN/ai-taro/mcp and /zh-CN/ai-taro/for-agents in the
Chinese page.
---
Nitpick comments:
In `@packages/nutui-react-cli-core/scripts/prepare-data.mjs`:
- Around line 58-65: 更新 copyRepoFile 上方注释,使其准确描述函数当前行为:relPosixPath
作为相对仓库根路径用于拼接源文件路径;移除关于使用 posix basename 或由该函数执行本地 join 的误导性表述。
In `@scripts/build-meta.mjs`:
- Around line 306-310: 在构建元数据的汇总输出中补充 noApiTaroIds 的明细日志:参考 noApiIds
的条件判断和输出格式,当 noApiTaroIds 非空时打印缺少 Taro API 表的组件数量及其 ID 列表,保留现有 H5 输出不变。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 31ed4977-8b71-494c-9cd4-d73e23c1fc2a
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (47)
package.jsonpackages/nutui-react-cli-core/.gitignorepackages/nutui-react-cli-core/package.jsonpackages/nutui-react-cli-core/scripts/prepare-data.mjspackages/nutui-react-cli-core/src/cli.tspackages/nutui-react-cli-core/src/commands/_shared.tspackages/nutui-react-cli-core/src/commands/demo.tspackages/nutui-react-cli-core/src/commands/doc.tspackages/nutui-react-cli-core/src/commands/info.tspackages/nutui-react-cli-core/src/commands/list.tspackages/nutui-react-cli-core/src/commands/mcp.tspackages/nutui-react-cli-core/src/commands/token.tspackages/nutui-react-cli-core/src/config.tspackages/nutui-react-cli-core/src/data.tspackages/nutui-react-cli-core/src/error.tspackages/nutui-react-cli-core/src/format.tspackages/nutui-react-cli-core/src/index.tspackages/nutui-react-cli-core/src/mcp/prompts.tspackages/nutui-react-cli-core/src/mcp/tools.tspackages/nutui-react-cli-core/src/types.tspackages/nutui-react-cli-core/tsconfig.jsonpackages/nutui-react-cli/package.jsonpackages/nutui-react-cli/scripts/prepare-data.mjspackages/nutui-react-cli/src/cli.tspackages/nutui-react-cli/src/mcp/prompts.tspackages/nutui-react-cli/src/mcp/tools.tspackages/nutui-react-cli/tsup.config.tspackages/nutui-react-taro-cli/.gitignorepackages/nutui-react-taro-cli/README.mdpackages/nutui-react-taro-cli/package.jsonpackages/nutui-react-taro-cli/scripts/prepare-data.mjspackages/nutui-react-taro-cli/skills/.npmignorepackages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.mdpackages/nutui-react-taro-cli/src/cli.tspackages/nutui-react-taro-cli/tsconfig.jsonpackages/nutui-react-taro-cli/tsup.config.tspnpm-workspace.yamlscripts/build-meta.mjsscripts/create-properties.jsscripts/properties-taro.jsonscripts/properties.jsonsrc/sites/sites-react/doc/docs/ai-taro/cli.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/cli.mdsrc/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/for-agents.mdsrc/sites/sites-react/doc/docs/ai-taro/mcp.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/mcp.md
💤 Files with no reviewable changes (2)
- packages/nutui-react-cli/src/mcp/prompts.ts
- packages/nutui-react-cli/src/mcp/tools.ts
| // 读取组件某语言的文档原文。快照期 prepare-data 已按 <lang>.md 落盘(zh.md / en.md), | ||
| // 故此处直接以 lang 寻址,无需 key 映射。缺失(如 Taro 无英文)返回 null。 | ||
| export function readDoc( | ||
| dataDir: string, | ||
| component: Component, | ||
| lang: Lang | ||
| ): string | null { | ||
| const file = path.join(dataDir, 'docs', component.id, `${lang}.md`) | ||
| return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win
readDoc 缺少对 lang 的路径穿越防护,存在任意 .md 文件读取风险。
readDoc 直接将 lang 拼进 ${lang}.md 而不做校验,与两个函数之后 readDemo 对 name 的防御处理(拦截 /、\\)不一致。CLI 入口通过 yargs choices: config.langs 限制了 --lang 取值,但 MCP doc 工具(mcp/tools.ts 的 createToolHandler)直接把外部传入的 params.lang 透传给 readDoc,未做任何白名单校验:
const lang = (params.lang as Lang) ?? config.defaultLang
const content = readDoc(config.dataDir, comp, lang)
当 MCP 客户端(或被提示注入操纵的 Agent)传入形如 ../../../../some/path 的 lang 时,可越出 dataDir/docs/<component.id>/ 目录读取文件系统中任意以 .md 结尾的文件内容并通过工具结果返回。建议直接在 readDoc 内部补上与 readDemo 一致的分隔符校验,一次性覆盖 CLI 与 MCP 两条调用链。
🛡️ 建议修复
export function readDoc(
dataDir: string,
component: Component,
lang: Lang
): string | null {
+ // 防御路径穿越:lang 可能来自 MCP 工具调用的外部输入。
+ if (lang.includes('/') || lang.includes('\\')) {
+ return null
+ }
const file = path.join(dataDir, 'docs', component.id, `${lang}.md`)
return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // 读取组件某语言的文档原文。快照期 prepare-data 已按 <lang>.md 落盘(zh.md / en.md), | |
| // 故此处直接以 lang 寻址,无需 key 映射。缺失(如 Taro 无英文)返回 null。 | |
| export function readDoc( | |
| dataDir: string, | |
| component: Component, | |
| lang: Lang | |
| ): string | null { | |
| const file = path.join(dataDir, 'docs', component.id, `${lang}.md`) | |
| return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null | |
| } | |
| // 读取组件某语言的文档原文。快照期 prepare-data 已按 <lang>.md 落盘(zh.md / en.md), | |
| // 故此处直接以 lang 寻址,无需 key 映射。缺失(如 Taro 无英文)返回 null。 | |
| export function readDoc( | |
| dataDir: string, | |
| component: Component, | |
| lang: Lang | |
| ): string | null { | |
| // 防御路径穿越:lang 可能来自 MCP 工具调用的外部输入。 | |
| if (lang.includes('/') || lang.includes('\\')) { | |
| return null | |
| } | |
| const file = path.join(dataDir, 'docs', component.id, `${lang}.md`) | |
| return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null | |
| } |
🧰 Tools
🪛 ast-grep (0.45.0)
[warning] 69-69: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(file, 'utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-cli-core/src/data.ts` around lines 62 - 71, 在 readDoc
中先校验 lang 不包含路径分隔符“/”或“\”,发现非法值时直接返回
null,再执行现有的文档路径拼接与读取逻辑;保持合法语言值及文件不存在时的行为不变,并与 readDemo 的防护方式一致。
| case 'doc': { | ||
| const comp = resolve(config, meta, params.component as string) | ||
| if (isError(comp)) return toMcpResult(comp) | ||
| const lang = (params.lang as Lang) ?? config.defaultLang | ||
| const content = readDoc(config.dataDir, comp, lang) | ||
| if (content === null) { | ||
| const langName = config.langLabel[lang] ?? lang | ||
| return toMcpResult( | ||
| createError( | ||
| ErrorCodes.DOC_NOT_FOUND, | ||
| `${comp.name} ${comp.cName} 暂无${langName}文档。` | ||
| ) | ||
| ) | ||
| } | ||
| return toMcpResult({ name: comp.name, lang, doc: content }) | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate files =="
fd -a 'tools\.ts|data\.ts|cli\.ts' . | sed 's#^\./##' | head -100
echo
echo "== relevant snippets =="
if [ -f packages/nutui-react-cli-core/src/mcp/tools.ts ]; then
echo "--- tools.ts around doc case ---"
nl -ba packages/nutui-react-cli-core/src/mcp/tools.ts | sed -n '170,240p'
fi
if [ -f packages/nutui-react-cli-core/src/mcp/data.ts ]; then
echo "--- data.ts readDoc/readDemo snippets ---"
rg -n "function readDoc|const readDoc|readDoc|function readDemo|const readDemo|readDemo|path\\.join|split|includes|config\\.langs" packages/nutui-react-cli-core/src/mcp/data.ts
nl -ba packages/nutui-react-cli-core/src/mcp/data.ts | sed -n '1,220p'
fi
if [ -f packages/nutui-react-cli-core/src/cli.ts ]; then
echo "--- cli.ts lang option ---"
nl -ba packages/nutui-react-cli-core/src/cli.ts | sed -n '1,220p'
fi
echo
echo "== package/sdk dependency versions if available =="
for f in package.json packages/nutui-react-cli-core/package.json pnpm-lock.yaml package-lock.json yarn.lock; do
if [ -f "$f" ]; then
echo "--- $f ---"
rg -n '"`@modelcontextprotocol/sdk`"|version' "$f" | head -80 || true
fi
doneRepository: jdf2e/nutui-react
Length of output: 575
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== installed tools =="
command -v sed awk grep node python3 || true
echo "== relevant snippets =="
echo "--- tools.ts around doc case ---"
sed -n '170,240p' packages/nutui-react-cli-core/src/mcp/tools.ts | awk '{printf "%5d\t%s\n", NR+169, $0}'
echo "--- data.ts outline/search ---"
grep -nE "readDoc|readDemo|path\\.join|\\.split\\(|include|config\\.langs|existsSync|readFileSync|resolve|basename" packages/nutui-react-cli-core/src/data.ts || true
echo "--- data.ts snippets mentioning readDoc/readDemo and paths ---"
python3 - <<'PY'
from pathlib import Path
p=Path('packages/nutui-react-cli-core/src/data.ts')
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
if 'function readDoc' in l or 'const readDoc' in l or 'function readDemo' in l or 'const readDemo' in l or 'path.join' in l or 'config.langs' in l:
start=max(1,i-8); end=min(len(lines),i+25)
print(f'### {p}:{i}')
for n in range(start,end+1):
print(f'{n:5d}\t{lines[n-1]}')
print()
PY
echo "--- cli.ts lang option snippets ---"
grep -nE "lang|choices|option|defaultLang|yargs|doc|nutui" packages/nutui-react-cli-core/src/cli.ts packages/nutui-react-cli/src/cli.ts || true
for f in packages/nutui-react-cli-core/src/cli.ts packages/nutui-react-cli/src/cli.ts packages/nutui-react-taro-cli/src/cli.ts; do
if [ -f "$f" ]; then
echo "### $f lang-related"
sed -n '/lang/,+80p' "$f" | awk '{printf "%5d\t%s\n", NR, $0}'
fi
done
echo "== package/sdk dependency versions if available =="
for f in package.json packages/nutui-react-cli-core/package.json pnpm-lock.yaml package-lock.json yarn.lock; do
if [ -f "$f" ]; then
echo "--- $f ---"
grep -nE '"`@modelcontextprotocol/sdk`"|version' "$f" | head -120 || true
fi
done
echo "== read-only path traversal probe from data.ts logic =="
python3 - <<'PY'
from pathlib import PurePosixPath, Path
# Model the likely readDoc path construction from data.ts without importing repo code.
data_dir = '/tmp/nutui-docs'
component = type('C', (), {'id':'button', 'name':'button', 'cName':'BTN'})()
lang = '../../../secret'
read_doc_path = str(PurePosixPath(data_dir, 'docs', component.id, f'{lang}.md'))
print(f'data_dir={data_dir} component.id={component.id} lang={lang!r}')
print(f'constructed_path={read_doc_path}')
print(f'normalized_starts_with_data_dir={PurePosixPath(read_doc_path).is_relative_to(data_dir)}')
print(f'substring_contains_conf={read_doc_path.find('docs/nutui.config.json') != -1}')
PYRepository: jdf2e/nutui-react
Length of output: 23689
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== installed tools =="
command -v sed awk grep node python3 || true
echo "== relevant snippets =="
echo "--- tools.ts around doc case ---"
sed -n '170,240p' packages/nutui-react-cli-core/src/mcp/tools.ts | awk '{printf "%5d\t%s\n", NR+169, $0}'
echo "--- data.ts outline/search ---"
grep -nE "readDoc|readDemo|path\\.join|\\.split\\(|include|config\\.langs|existsSync|readFileSync|resolve|basename" packages/nutui-react-cli-core/src/data.ts || true
echo "--- data.ts snippets mentioning readDoc/readDemo and paths ---"
python3 - <<'PY'
from pathlib import Path
p=Path('packages/nutui-react-cli-core/src/data.ts')
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
if 'function readDoc' in l or 'const readDoc' in l or 'function readDemo' in l or 'const readDemo' in l or 'path.join' in l or 'config.langs' in l:
start=max(1,i-8); end=min(len(lines),i+25)
for n in range(start,end+1):
print(f'{n:5d}\t{lines[n-1]}')
print()
PY
echo "--- cli.ts lang option snippets ---"
grep -nE "lang|choices|option|defaultLang|yargs|doc|nutui" packages/nutui-react-cli-core/src/cli.ts packages/nutui-react-cli/src/cli.ts || true
for f in packages/nutui-react-cli-core/src/cli.ts packages/nutui-react-cli/src/cli.ts packages/nutui-react-taro-cli/src/cli.ts; do
if [ -f "$f" ]; then
echo "### $f lang-related"
sed -n '/lang/,+80p' "$f" | awk '{printf "%5d\t%s\n", NR, $0}'
fi
done
echo "== package/sdk dependency versions if available =="
for f in package.json packages/nutui-react-cli-core/package.json pnpm-lock.yaml package-lock.json yarn.lock; do
if [ -f "$f" ]; then
echo "--- $f ---"
grep -nE '"`@modelcontextprotocol/sdk`"|version' "$f" | head -120 || true
fi
done
echo "== read-only path traversal probe from data.ts logic =="
python3 - <<'PY'
from pathlib import PurePosixPath
data_dir = '/tmp/nutui-docs'
component_id = 'button'
for lang in ['zh-CN', '../../../secret', '../docs/nutui.config.json']:
path = str(PurePosixPath(data_dir, 'docs', component_id, f'{lang}.md'))
rel_ok = Path(path).is_relative_to(data_dir) if hasattr(PurePosixPath, 'is_relative_to') else Path(path).resolve().parent == Path(data_dir).resolve().parent
conf_hit = 'docs/nutui.config.json' in path
print(f'lang={lang!r:24} path={path} relative_to_data={rel_ok} contains_config_path={conf_hit}')
PYRepository: jdf2e/nutui-react
Length of output: 23293
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== deterministic path traversal probe =="
node - <<'JS'
const path = require('node:path');
const dataDir = '/tmp/nutui-docs';
const component = { id: 'button' };
for (const lang of ['zh', '../../../secret', '../docs/nutui.config.json']) {
const file = path.join(dataDir, 'docs', component.id, `${lang}.md`);
console.log(JSON.stringify({ lang, constructedPath: file }));
}
JS
echo
echo "== MCP tools definitions around runCli/server/register call =="
rg -n "buildToolDefinitions|setRequestHandler|CallToolRequestSchema|registerTool|Server|runCli|mcp:" packages/nutui-react-cli-core/src packages/nutui-react-cli/src packages/nutui-react-taro-cli/src || trueRepository: jdf2e/nutui-react
Length of output: 3373
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== deterministic path traversal probe =="
node - <<'JS'
const path = require('node:path');
const dataDir = '/tmp'nutui-docs';
const component = { id: 'button' };
for (const lang of ['zh', '../../../secret', '../docs/nutui.config.json']) {
const file = path.join(dataDir, 'docs', component.id, `${lang}.md`);
console.log(JSON.stringify({ lang, constructedPath: file }));
}
JS
echo
echo "== MCP tools definitions around runCli/server/register call =="
rg -n "buildToolDefinitions|setRequestHandler|CallToolRequestSchema|registerTool|Server|runCli|mcp:" packages/nutui-react-cli-core/src packages/nutui-react-cli/src packages/nutui-react-taro-cli/src || trueRepository: jdf2e/nutui-react
Length of output: 824
在 MCP 入口校验 lang,不要让 readDoc 直接凭 path.join 处理外部输入。
doc 工具通过 setRequestHandler(CallToolRequestSchema, ...) 处理请求,工具定义的 enum 只是 Schema 说明;lang 会进入 readDoc,而 readDoc 用 ${lang}.md 直接拼接路径,../../../secret 这类输入会构造出 /tmp/secret.md 并读取。CLI 的 yargs choices 不能覆盖 MCP 工具调用路径,需在 handler 或 readDoc 内比照 readDemo 做语言白名单/路径分隔符拦截。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-cli-core/src/mcp/tools.ts` around lines 210 - 225, 在 MCP
请求处理的 doc 分支中校验 params.lang,仅允许配置支持的语言值,并拒绝包含路径分隔符或其他非法路径片段的输入;校验通过后再调用
readDoc,确保外部输入不会被拼接为任意文件路径。复用 readDemo 的语言白名单校验方式,并保留默认语言处理逻辑。
|
|
||
| ```bash | ||
| npm i -D @nutui/nutui-react-taro-cli | ||
| npx skills add ./node_modules/@nutui/nutui-react-taro-cli/skills/nutui-react-taro |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
npm npx default behavior prompts before executing package prompt question confirmation --yes
💡 Result:
By default, npx prompts the user for confirmation before installing any package that is not already present in the local project dependencies [1][2]. This safety measure is designed to prevent security issues and user errors resulting from mistyped package names [1][3][2]. When npx triggers this prompt, it pauses execution and requires the user to manually type "yes" to proceed with the installation and execution of the package [4]. To suppress this prompt and automatically allow the installation, you can use the --yes (or -y) flag [1][2]. For example: npx --yes package-name Additionally, the prompt is automatically bypassed in environments where standard input (stdin) is not available, such as in many non-interactive CI/CD pipelines [4]. You can also force this behavior by setting the environment variable npm_config_yes=true [4].
Citations:
- 1: https://docs.npmjs.com/cli/v8/commands/npx/
- 2: https://docs.npmjs.com/cli/v11/commands/npx/
- 3: https://github.com/npm/cli/blob/latest/docs/lib/content/commands/npx.md
- 4: [BUG] New --yes behavior in npx is a breaking change that can't easily be handled npm/cli#2226
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate files =="
git ls-files | rg '(^|/)README\.md$|for-agents\.(en-US|zh-CN)?\.md$' || true
echo
echo "== command occurrences =="
rg -n "npx (skills add|`@nutui/nutui-react-taro-cli` info Button)|ForAgent|for agents|agent" \
packages/nutui-react-taro-cli/README.md \
src/sites/sites-react/doc/docs/ai-taro || true
echo
echo "== relevant doc slices =="
sed -n '96,112p' packages/nutui-react-taro-cli/README.md || true
sed -n '18,30p' src/sites/sites-react/doc/docs/ai-taro/for-agents.md || true
if [ -f src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md ]; then
sed -n '18,30p' src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md || true
fiRepository: jdf2e/nutui-react
Length of output: 6683
统一为 Agent 就绪的非交互式 npx 命令。
这些命令面向 Agent 自动化流程,首次执行未缓存的 npm 包时应避免等待安装确认;建议把示例中的 npx skills add 和 npx @nutui/nutui-react-taro-cli info Button 改为 npx -y ...,并补全相关 for-agents*.md 文件中的同类命令。
📍 Affects 3 files
packages/nutui-react-taro-cli/README.md#L106-L106(this comment)src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md#L24-L24src/sites/sites-react/doc/docs/ai-taro/for-agents.md#L24-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/nutui-react-taro-cli/README.md` at line 106, 将
packages/nutui-react-taro-cli/README.md 第106行的 skills add
命令、src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md 第24行及
src/sites/sites-react/doc/docs/ai-taro/for-agents.md 第24行的相关 npx 命令统一改为带 -y
参数,覆盖 skills add 和 `@nutui/nutui-react-taro-cli` info Button,确保首次执行时保持非交互式。
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 8
🧹 Nitpick comments (2)
scripts/build-meta.mjs (1)
306-310: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
noApiTaroIds只参与计数,未输出明细。 H5 侧会列出缺少 API 表的组件 id,taro 侧同样收集了noApiTaroIds却没有打印,排查 Taro 端缺表组件时只能看到一个总数。🔎 建议补充 taro 侧明细输出
if (noApiIds.length) { console.log(` 无 API 表(H5)的组件 (${noApiIds.length}): ${noApiIds.join(', ')}`) } + if (noApiTaroIds.length) { + console.log(` 无 API 表(taro)的组件 (${noApiTaroIds.length}): ${noApiTaroIds.join(', ')}`) + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/build-meta.mjs` around lines 306 - 310, 在构建元数据的汇总输出中补充 noApiTaroIds 的明细日志:参考 noApiIds 的条件判断和输出格式,当 noApiTaroIds 非空时打印缺少 Taro API 表的组件数量及其 ID 列表,保留现有 H5 输出不变。packages/nutui-react-cli-core/scripts/prepare-data.mjs (1)
58-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value注释与实现不一致。 该函数并未使用 posix
basename(basename 由调用方在 demos 分支处理),注释容易误导后续维护者。📝 建议修正注释
-// meta 里的路径始终是 posix 相对仓库根路径,用 posix 取 basename,再 join 到本地。 +// meta 里的路径始终是 posix 相对仓库根路径,这里按仓库根解析后复制到目标绝对路径。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nutui-react-cli-core/scripts/prepare-data.mjs` around lines 58 - 65, 更新 copyRepoFile 上方注释,使其准确描述函数当前行为:relPosixPath 作为相对仓库根路径用于拼接源文件路径;移除关于使用 posix basename 或由该函数执行本地 join 的误导性表述。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/nutui-react-cli-core/src/data.ts`:
- Around line 62-71: 在 readDoc 中先校验 lang 不包含路径分隔符“/”或“\”,发现非法值时直接返回
null,再执行现有的文档路径拼接与读取逻辑;保持合法语言值及文件不存在时的行为不变,并与 readDemo 的防护方式一致。
In `@packages/nutui-react-cli-core/src/mcp/tools.ts`:
- Around line 210-225: 在 MCP 请求处理的 doc 分支中校验
params.lang,仅允许配置支持的语言值,并拒绝包含路径分隔符或其他非法路径片段的输入;校验通过后再调用
readDoc,确保外部输入不会被拼接为任意文件路径。复用 readDemo 的语言白名单校验方式,并保留默认语言处理逻辑。
In `@packages/nutui-react-taro-cli/README.md`:
- Line 106: 将 packages/nutui-react-taro-cli/README.md 第106行的 skills add
命令、src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md 第24行及
src/sites/sites-react/doc/docs/ai-taro/for-agents.md 第24行的相关 npx 命令统一改为带 -y
参数,覆盖 skills add 和 `@nutui/nutui-react-taro-cli` info Button,确保首次执行时保持非交互式。
- Around line 73-86: Update the MCP configuration documentation in
packages/nutui-react-taro-cli/README.md (lines 73-86),
src/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.md (lines 31-42),
src/sites/sites-react/doc/docs/ai-taro/for-agents.md (lines 29-42),
src/sites/sites-react/doc/docs/ai-taro/mcp.en-US.md (lines 36-47), and
src/sites/sites-react/doc/docs/ai-taro/mcp.md (lines 36-47) to preserve
mcpServers for Claude and Cursor while providing a separate VS Code
.vscode/mcp.json example using the top-level servers field.
In `@packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md`:
- Around line 11-14: 统一锁定 CLI、Skill 和 MCP 使用的 `@nutui/nutui-react-taro-cli`
精确版本,移除“始终使用最新版”等未锁定表述。更新
packages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.md 的
allowed-tools(11-14)、CLI 示例(23-32)及 MCP args(98-104);更新
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md(24-28、76-80)和
src/sites/sites-react/doc/docs/ai-taro/cli.md(24-28、76-80),将 npx、npm i -D 及
skills add 命令统一使用同一明确版本。
In `@scripts/properties-taro.json`:
- Around line 3082-3091: 修正源文档 doc.taro.md 中 Form.labelPosition
表格行的反引号与竖线转义,使类型和默认值分别正确解析为 'top' 与 'left';同时将 Row.onClick 的英文说明 “Fired when
clicked” 改为与中文文档一致的描述。完成后重新执行 npm run generate:props:taro 生成
scripts/properties-taro.json,勿直接修改生成文件。
In `@scripts/properties.json`:
- Around line 7615-7621: 修正 doc.md 中 Popup.portal 和 TextArea.status
的类型字符串,移除多余的反引号并保持类型内容准确;随后运行 npm run generate:props,更新由属性文档生成的站点 API 表及
llms/MCP 输出。
In `@src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md`:
- Around line 85-89: Update all four documented MCP links in
src/sites/sites-react/doc/docs/ai-taro/cli.en-US.md lines 85-89 and 91, and
src/sites/sites-react/doc/docs/ai-taro/cli.md lines 85-89 and 91, to preserve
the Taro route context: use /en-US/ai-taro/mcp and /en-US/ai-taro/for-agents in
the English page, and /zh-CN/ai-taro/mcp and /zh-CN/ai-taro/for-agents in the
Chinese page.
---
Nitpick comments:
In `@packages/nutui-react-cli-core/scripts/prepare-data.mjs`:
- Around line 58-65: 更新 copyRepoFile 上方注释,使其准确描述函数当前行为:relPosixPath
作为相对仓库根路径用于拼接源文件路径;移除关于使用 posix basename 或由该函数执行本地 join 的误导性表述。
In `@scripts/build-meta.mjs`:
- Around line 306-310: 在构建元数据的汇总输出中补充 noApiTaroIds 的明细日志:参考 noApiIds
的条件判断和输出格式,当 noApiTaroIds 非空时打印缺少 Taro API 表的组件数量及其 ID 列表,保留现有 H5 输出不变。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 31ed4977-8b71-494c-9cd4-d73e23c1fc2a
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (47)
package.jsonpackages/nutui-react-cli-core/.gitignorepackages/nutui-react-cli-core/package.jsonpackages/nutui-react-cli-core/scripts/prepare-data.mjspackages/nutui-react-cli-core/src/cli.tspackages/nutui-react-cli-core/src/commands/_shared.tspackages/nutui-react-cli-core/src/commands/demo.tspackages/nutui-react-cli-core/src/commands/doc.tspackages/nutui-react-cli-core/src/commands/info.tspackages/nutui-react-cli-core/src/commands/list.tspackages/nutui-react-cli-core/src/commands/mcp.tspackages/nutui-react-cli-core/src/commands/token.tspackages/nutui-react-cli-core/src/config.tspackages/nutui-react-cli-core/src/data.tspackages/nutui-react-cli-core/src/error.tspackages/nutui-react-cli-core/src/format.tspackages/nutui-react-cli-core/src/index.tspackages/nutui-react-cli-core/src/mcp/prompts.tspackages/nutui-react-cli-core/src/mcp/tools.tspackages/nutui-react-cli-core/src/types.tspackages/nutui-react-cli-core/tsconfig.jsonpackages/nutui-react-cli/package.jsonpackages/nutui-react-cli/scripts/prepare-data.mjspackages/nutui-react-cli/src/cli.tspackages/nutui-react-cli/src/mcp/prompts.tspackages/nutui-react-cli/src/mcp/tools.tspackages/nutui-react-cli/tsup.config.tspackages/nutui-react-taro-cli/.gitignorepackages/nutui-react-taro-cli/README.mdpackages/nutui-react-taro-cli/package.jsonpackages/nutui-react-taro-cli/scripts/prepare-data.mjspackages/nutui-react-taro-cli/skills/.npmignorepackages/nutui-react-taro-cli/skills/nutui-react-taro/SKILL.mdpackages/nutui-react-taro-cli/src/cli.tspackages/nutui-react-taro-cli/tsconfig.jsonpackages/nutui-react-taro-cli/tsup.config.tspnpm-workspace.yamlscripts/build-meta.mjsscripts/create-properties.jsscripts/properties-taro.jsonscripts/properties.jsonsrc/sites/sites-react/doc/docs/ai-taro/cli.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/cli.mdsrc/sites/sites-react/doc/docs/ai-taro/for-agents.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/for-agents.mdsrc/sites/sites-react/doc/docs/ai-taro/mcp.en-US.mdsrc/sites/sites-react/doc/docs/ai-taro/mcp.md
💤 Files with no reviewable changes (2)
- packages/nutui-react-cli/src/mcp/prompts.ts
- packages/nutui-react-cli/src/mcp/tools.ts
🛑 Comments failed to post (2)
scripts/properties-taro.json (1)
3082-3091: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
生成物暴露了源
doc.taro.md的表格书写问题。Form.labelPosition的类型被解析成"\\`\\`'top'"、默认值成"'left'\\",说明源 markdown 该行的反引号/竖线转义有误;这些值会原样进入apiTaro并出现在站点 API 表与 CLI/MCP 输出里。另外第 758 行Row.onClick的说明为英文 “Fired when clicked”,与中文文档不一致。请修改对应组件的doc.taro.md后重新执行npm run generate:props:taro,而不是直接改本文件。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/properties-taro.json` around lines 3082 - 3091, 修正源文档 doc.taro.md 中 Form.labelPosition 表格行的反引号与竖线转义,使类型和默认值分别正确解析为 'top' 与 'left';同时将 Row.onClick 的英文说明 “Fired when clicked” 改为与中文文档一致的描述。完成后重新执行 npm run generate:props:taro 生成 scripts/properties-taro.json,勿直接修改生成文件。scripts/properties.json (1)
7615-7621: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Popup.portal的类型字符串反引号不配对。"`HTMLElement` | `(() => HTMLElement)` | null`"末尾多出一个反引号,渲染到站点 API 表与 llms/MCP 输出时会出现残留符号。类似的还有TextArea.status的"`default /\\ error`"(第 5739 行)。请修正对应doc.md表格后重跑npm run generate:props。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/properties.json` around lines 7615 - 7621, 修正 doc.md 中 Popup.portal 和 TextArea.status 的类型字符串,移除多余的反引号并保持类型内容准确;随后运行 npm run generate:props,更新由属性文档生成的站点 API 表及 llms/MCP 输出。
背景
本仓库产出两个 npm 包:
@nutui/nutui-react(H5)与@nutui/nutui-react-taro(Taro 跨端)。此前面向 AI-Coding 的能力(CLI + MCP + Skill + 站点ai/*文档)只覆盖 H5 端:@nutui/nutui-react-cli仅服务 H5(数据快照只取 H5 端 docs/demos)。ai-taro/只有 llms.md,而 nav 的 AI 子菜单(For Agents / CLI / MCP)为 H5/Taro 共用,导致 Taro 站点这三个菜单点进去 404。本 PR 用与 H5 完全对称的思路,给 Taro 端补齐全套能力。
改动概览
数据层(
scripts/)create-properties.js:传taro参数时输出properties-taro.json(扫doc.taro.md),不再覆盖 H5 的properties.json。build-meta.mjs:每个组件新增apiTaro字段(Taro 端 Props),与 H5 的api并存。实测 29 个组件两端 Props 存在真实差异(如 Button 的type:H5 含service、Taro 不含)。package.json:新增generate:props/generate:props:taro脚本;prebuild:site/prebuild:taro:site分别串联对应端的 props 生成。properties.json(与当前doc.md重新同步,记录数 930 → 1174)。CLI 层(
packages/)@nutui/nutui-react-cli-core(private,不发布):承载全部命令 / MCP / 数据查询逻辑,平台差异收敛到CliConfig接口。@nutui/nutui-react-cli(H5)瘦身为薄壳:仅保留构造 H5CliConfig的入口,委托 core,行为零回归。@nutui/nutui-react-taro-cli:bin: nutui-react-taro,MCP servernutui-react-taro,仅中文文档,数据取apiTaro/demos.taro。含独立 SKILL.md 与 README。dist/cli.js(零运行时依赖);core 以workspace:*devDependency 引入,发布安全(消费者不会去 registry 找未发布的 core)。站点文档(
src/sites/sites-react/doc/docs/ai-taro/)aiTaroRoutes已按 glob 自动收录,无需改路由 / nav。验证
build成功,产物已内联 core、无对 core 的运行时 importlist头部显示「Taro 多端」、info Button取 apiTaro(无 service)、demo取 Taro 示例、doc --lang en因单语言不注册该选项nutui-react-taro、5 个nutui_*工具、nutui_doc的 lang enum 仅["zh"]npm run build:taro:site成功,6 篇 ai-taro 文档均编译为独立 chunk备注
properties.json的大范围 diff 是过时数据的同步刷新,与本 PR 同批提交。Summary by CodeRabbit
新功能
文档